package com.yizhang.newfeatures;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.*;

/**
 * 简单流
 * @param <T>
 */
public class SimpleStream<T> {

    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5, 1);
        SimpleStream.of(list)
                .filter(x -> (x & 1) == 1)
                .map(x -> x * x)
                .forEach(System.out::println);

        // 化简
        System.out.println(SimpleStream.of(list).reduce(0, Integer::sum));
        System.out.println(SimpleStream.of(list).reduce(Integer.MIN_VALUE, Integer::max));
        System.out.println(SimpleStream.of(list).reduce(Integer.MAX_VALUE, Integer::min));

        // 收集
        HashSet<Integer> collect = SimpleStream.of(list).collect(HashSet::new, HashSet::add);
        System.out.println(collect);

        StringBuilder builder = SimpleStream.of(list).collect(StringBuilder::new, StringBuilder::append);
        System.out.println(builder);

        StringJoiner result = SimpleStream.of(list)
                .collect(() -> new StringJoiner("-"), (joiner, item) -> joiner.add(String.valueOf(item)));
        StringJoiner result1 = SimpleStream.of(list).map(String::valueOf).collect(() -> new StringJoiner("-"), StringJoiner::add);
        System.out.println(result);
        System.out.println(result1);

        HashMap<Integer, Integer> map = SimpleStream.of(list)
                .collect(HashMap::new,
                        (hashMap, item) -> hashMap.put(item, hashMap.getOrDefault(item, 0) + 1));
        // 当hashMap中检测到键item不存在时，就会执行k->new AtomicInteger()  其中k的值就是item的值
        HashMap<Integer, AtomicInteger> map1 = SimpleStream.of(list)
                .collect(HashMap::new,
                        (hashMap, item) -> hashMap.computeIfAbsent(item, k -> new AtomicInteger()).incrementAndGet());
        System.out.println(map);
        System.out.println(map1);
    }

    private Collection<T> collection;

    private SimpleStream(Collection<T> collection) {
        this.collection = collection;
    }

    public static <U> SimpleStream<U> of(Collection<U> collection) {
        return new SimpleStream<>(collection);
    }

    public SimpleStream<T> filter(Predicate<T> predicate) {
        List<T> list = new ArrayList<>();
        for (T item : collection) {
            if (predicate.test(item)) {
                list.add(item);
            }
        }
        return new SimpleStream<>(list);
    }

    public <R> SimpleStream<R> map(Function<T, R> function) {
        List<R> list = new ArrayList<>();
        for (T item : collection) {
            list.add(function.apply(item));
        }
        return new SimpleStream<>(list);
    }

    public void forEach(Consumer<T> consumer) {
        for (T item : collection) {
            consumer.accept(item);
        }
    }

    public T reduce(T o, BinaryOperator<T> operator) {
        T result = o;
        for (T item : collection) {
            result = operator.apply(result, item);
        }
        return result;
    }

    public <C> C collect(Supplier<C> supplier, BiConsumer<C, T> consumer) {
        C c = supplier.get();
        for (T item : collection) {
            consumer.accept(c, item);
        }
        return c;
    }
}
